package com.example.demo.common;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

import static java.util.stream.Collectors.toList;

/**
 *
 * webflux-返回统一的自定义响应对象 https://segmentfault.com/a/1190000021205525?utm_source=tag-newest
 * @author fanhb on 2020/8/6
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class R {

    @JsonProperty("REQ_BODY")
    private Body body;
    @JsonProperty("REQ_HEAD")
    private Head head;

    public R(Body body, Head head) {
        this.body = body;
        this.head = head;
    }

    public static R ok() {
        Head head = new Head();
        Body body = new Body();
        head.ok();
        return new R(body, head);
    }
    public static R error() {
        Head head = new Head();
        Body body = new Body();
        head.error();
        return new R(body, head);
    }
    public static R error(String errorCOde,String errorMsg) {
        Head head = new Head();
        Body body = new Body();
        head.setErrorCode(errorCOde);
        head.setErrorMsg(errorMsg);
        return new R(body, head);
    }

    /**
     * 封装返回列表
     * @param flux reactive返回的列表数据
     * @param <T> 数据实际类型
     */
    public <T> Mono<R> body(Flux<T> flux) {
        return flux.collect(toList()).map(this::bodyList);
    }

    private  <T> R bodyList(List<T> list) {
        body.setData(list);
        return this;
    }

    /**
     * 封装单个返回结果
     * @param monoData reactive返回的单个数据
     * @param <T> 返回数据的实际类型
     */
    public <T> Mono<R> body(Mono<T> monoData) {
        return monoData.map(this::bodyMono);
    }
    /**
     * 合并总记录数和查询结果
     */
    public <T> Mono<R> body(Mono<T> monoData,Mono<Long> count) {
        return monoData.zipWith(count).map(o->{
            this.body.setData(o.getT1());
            this.body.setCount(o.getT2());
            return this;
        });
    }

    private  <T> R bodyMono(T data) {
        body.setData(data);
        return this;
    }


}
